package com.yx.fsysserver.file.service;

import com.yx.fsysserver.common.BaseService;
import com.yx.fsysserver.common.exception.ServiceException;
import com.yx.fsysserver.file.component.FileAccessComp;
import com.yx.fsysserver.file.dao.FileInfoMapper;
import com.yx.fsysserver.file.dao.VrFileInfoMapper;
import com.yx.fsysserver.file.domain.FileInfo;
import com.yx.fsysserver.file.domain.VrFileInfo;
import com.yx.fsysserver.file.vo.UploadResult;
import com.yx.fsysserver.utils.UnCompressor;
import com.yx.lib.http.HttpTookit;
import com.yx.lib.utils.DigestUtils;
import com.yx.lib.utils.FileInfoUtils;
import com.yx.lib.utils.file.SuffixUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * 文件服务
 * Created by lichagnfeng on 2017/3/6.
 */
@Service
public class FileService extends BaseService<FileInfo> {
    private static Logger log = LoggerFactory.getLogger(FileService.class);

    @Autowired
    private FileInfoMapper fileInfoMapper;
    @Autowired
    private VrFileInfoMapper vrFileInfoMapper;

    @Autowired
    private FileAccessComp fileAccessComp;

    @Autowired
    private AliOssService aliOssService;

    @Value("${file.upload.tmp.path}")
    private String uploadTmpPath;
    @Value("${file.storage.path}")
    private String fileSavePath;
    @Value("${api.prefix.path}")
    private String apiPreFixPath;
    @Value("${core.data.host}")
    private String coreDataHost;

    @Resource(name = "fileInfoMapper")
    public void setFileInfoMapper(FileInfoMapper fileInfoMapper) {
        setMapper(fileInfoMapper);
        this.fileInfoMapper = fileInfoMapper;
    }

    /**
     * 上传文件
     * @param inputStream
     * @param fileName
     * @return
     */
    public UploadResult uploadFile(InputStream inputStream, String fileName){

        FileOutputStream fos = null;
        try {
            String suffix = FileInfoUtils.getFileSuffix(fileName);
            String fileNameNoSuffix = FileInfoUtils.getFileNameNoSuffix(fileName);

            String uuid = UUID.randomUUID().toString();
            String newFileName = uuid+"."+suffix;

            //写入临时文件夹
            String dateStr = DateFormatUtils.format(new Date(),"yyyy-MM-dd");
            String newFileTmpPath = uploadTmpPath+dateStr+"/"+newFileName;
            File newFileTmp = new File(newFileTmpPath);
            FileUtils.forceMkdir(newFileTmp.getParentFile());
            fos = new FileOutputStream(newFileTmpPath);
            IOUtils.copy(inputStream,fos);

            //获取文件相关信息
            long fileSize = newFileTmp.length();
            //获取md5 和sha1
            String md5Code = DigestUtils.getFileDigestCode(newFileTmp,"md5");
            String sha1Code = DigestUtils.getFileDigestCode(newFileTmp,"sha1");

            //查看是否已经存在
            /*FileInfo queryObj = new FileInfo();
            queryObj.setMd5Code(md5Code);
            queryObj.setSha1Code(sha1Code);
            List<FileInfo> queryList = this.fileInfoMapper.select(queryObj);
            if (queryList.size() > 0){
                FileInfo oldFileInfo = queryList.get(0);
                String typeStr = SuffixUtil.getTypeBySuffix(suffix);
                // 原文件位置
                String oldPath = oldFileInfo.getPath();
                oldPath = fileSavePath + typeStr + oldPath.substring(oldPath.lastIndexOf(typeStr)+typeStr.length());
                // 物理文件是否存在
                File file = new File(oldPath);
                if (!file.exists()){
                    String oldFileName = oldPath.substring(oldPath.lastIndexOf("/")+1);
                    String oldFileDir = oldPath.substring(0, oldPath.lastIndexOf("/")+1);
                    // 文件不存在，获取原文件地址，将新文件上传至原数据路径下
                    this.fileAccessComp.write(new FileInputStream(newFileTmp),oldFileDir, oldFileName);
                    UploadResult result = new UploadResult(true,"上传成功",fileNameNoSuffix,fileNameNoSuffix,fileSize,oldFileInfo.getPath(),oldFileInfo.getPathView(),suffix);
                    return  result;
                }else{
                    UploadResult result = new UploadResult(true,"上传成功",fileNameNoSuffix,fileNameNoSuffix,fileSize,oldFileInfo.getPath(),oldFileInfo.getPathView(),suffix);
                    return  result;
                }
            }*/

            //把文件放入正式存储
            String typeStr = SuffixUtil.getTypeBySuffix(suffix);
            String saveDir = fileSavePath+typeStr+"/"+dateStr+"/";
            this.fileAccessComp.write(newFileTmp,saveDir);

            //写入数据库
            FileInfo fileInfo = new FileInfo();
            String newFilePath = apiPreFixPath + typeStr+"/"+dateStr+"/"+newFileName;
            log.info("newFilePath:"+newFilePath);
            fileInfo.setPath(newFilePath);
            fileInfo.setPathView(newFilePath);
            fileInfo.setName(newFileName);
            fileInfo.setSrcName(fileName);
            fileInfo.setSize(fileSize);
            fileInfo.setSuffix(suffix);
            fileInfo.setIsValid(1);
            fileInfo.setMd5Code(md5Code);
            fileInfo.setSha1Code(sha1Code);
            this.fileInfoMapper.insertSelective(fileInfo);

            UploadResult result = new UploadResult(true,"上传成功",fileNameNoSuffix,fileNameNoSuffix,fileSize,newFilePath,newFilePath,suffix);

            return result;

        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("upload error.",e);
        }finally {
            if (fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new ServiceException("close error.",e);
                }
            }
        }


    }


    /**
     * 上传压缩文件，需要解压成目录
     * @param inputStream
     * @param fileName
     * @return
     */
    public UploadResult uploadDirFile(InputStream inputStream, String fileName){
        FileOutputStream fos = null;
        try {
            String suffix = FileInfoUtils.getFileSuffix(fileName);
            String fileNameNoSuffix = FileInfoUtils.getFileNameNoSuffix(fileName);

            String uuid = UUID.randomUUID().toString();
            String newFileName = uuid+"."+suffix;

            //写入临时文件夹
            String dateStr = DateFormatUtils.format(new Date(),"yyyy-MM-dd");
            String newFileTmpPath = uploadTmpPath+dateStr+"/"+uuid+"/"+newFileName;
            File newFileTmp = new File(newFileTmpPath);
            FileUtils.forceMkdir(newFileTmp.getParentFile());
            fos = new FileOutputStream(newFileTmp);
            IOUtils.copy(inputStream,fos);

            //获取文件相关信息
            long fileSize = newFileTmp.length();
            //获取md5 和sha1
            String md5Code = DigestUtils.getFileDigestCode(newFileTmp,"md5");
            String sha1Code = DigestUtils.getFileDigestCode(newFileTmp,"sha1");

            //查看是否已经存在
            FileInfo queryObj = new FileInfo();
            queryObj.setMd5Code(md5Code);
            queryObj.setSha1Code(sha1Code);
            List<FileInfo> queryList = this.fileInfoMapper.select(queryObj);
            if (queryList.size()>0){
                FileInfo oldFileInfo = queryList.get(0);
                UploadResult result = new UploadResult(true, "上传成功", fileNameNoSuffix, fileNameNoSuffix, fileSize, oldFileInfo.getPath(), oldFileInfo.getPathView(), suffix);
                return result;
            }

            //解压缩
            UnCompressor.unzip(newFileTmp,newFileTmp.getParentFile());

            //把文件放入正式存储
            //String typeStr = SuffixUtil.getTypeBySuffix(suffix);
            String typeStr = "webhtml";
            String saveDir = fileSavePath+typeStr+"/"+dateStr+"/"+uuid;
            this.fileAccessComp.writeDir(newFileTmp.getParentFile(),saveDir);

            //写入数据库
            FileInfo fileInfo = new FileInfo();
            String newFilePathView = apiPreFixPath + typeStr+"/"+dateStr+"/"+uuid+"/index.html";
            String newFilePath = apiPreFixPath + typeStr+"/"+dateStr+"/"+uuid+"/"+uuid+"."+suffix;

            fileInfo.setPath(newFilePath);
            fileInfo.setPathView(newFilePathView);
            fileInfo.setName(newFileName);
            fileInfo.setSrcName(fileName);
            fileInfo.setSize(fileSize);
            fileInfo.setSuffix(suffix);
            fileInfo.setMd5Code(md5Code);
            fileInfo.setSha1Code(sha1Code);
            this.fileInfoMapper.insertSelective(fileInfo);
            UploadResult result = new UploadResult(true,"上传成功",fileNameNoSuffix,fileNameNoSuffix,fileSize,newFilePath,newFilePathView,suffix);

            return result;

        }catch (Exception e){
            throw new ServiceException("upload error.",e);
        }finally {
            if (fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new ServiceException("close error.",e);
                }
            }
        }


    }


    public void insert(FileInfo fileInfo){
        this.fileInfoMapper.insertSelective(fileInfo);
    }


    public FileInfo getFileInfoByPath(String path){
        FileInfo queryObj = new FileInfo();
        queryObj.setPath(path);
        List<FileInfo> list = this.fileInfoMapper.select(queryObj);
        if (list.size()>0){
            FileInfo fileInfo = list.get(0);
            return fileInfo;
        }else {
            throw new ServiceException("文件："+path+" 不存在.");
        }
    }

    public InputStream getInputStreamByPath(String path) throws Exception {
        String filePath = this.fileSavePath+path;
        InputStream is = null;
        is = this.fileAccessComp.read(filePath);

        return is;
    }

    public Long getFileLength(String path){
        String filePath = this.fileSavePath+path;

        return this.fileAccessComp.getFileLength(filePath);
    }


    /**
     * 上传压缩文件，需要解压成目录
     * @param inputStream
     * @param fileName
     * author qyb
     * @return
     */
    public UploadResult uploadVrFile(InputStream inputStream, String fileName){
        FileOutputStream fos = null;
        try {
            String suffix = FileInfoUtils.getFileSuffix(fileName);
            String fileNameNoSuffix = FileInfoUtils.getFileNameNoSuffix(fileName);
            String uuid = UUID.randomUUID().toString();
            String newFileName = uuid+"."+suffix;
            //写入临时文件夹
            String dateStr = DateFormatUtils.format(new Date(),"yyyy-MM-dd");
            String newFileTmpPath = uploadTmpPath+dateStr+"/"+uuid+"/"+newFileName;
            File newFileTmp = new File(newFileTmpPath);
            FileUtils.forceMkdir(newFileTmp.getParentFile());
            fos = new FileOutputStream(newFileTmp);
            IOUtils.copy(inputStream,fos);
            //获取文件相关信息
            long fileSize = newFileTmp.length();
            //解压缩并且上传服务器
            UnCompressor.unzip(newFileTmp,newFileTmp.getParentFile());
            String path = "";
            VrFileInfo vrFileInfoEP = new VrFileInfo();

            //vr 上传oss
            vrFileInfoEP = aliOssService.unzipVr(newFileTmp, newFileTmp.getParentFile(),uuid);

            //把文件放入正式存储
            String typeStr = "webhtml";
            String saveDir = fileSavePath+typeStr+"/"+dateStr+"/"+uuid;
            this.fileAccessComp.writeDir(newFileTmp.getParentFile(),saveDir);

            //写入数据库
            VrFileInfo vrFileInfo = new VrFileInfo();
            String newFilePath = apiPreFixPath + typeStr+"/"+dateStr+"/"+uuid+"/"+uuid+"."+suffix;

            //相对路径
            vrFileInfo.setPath(newFilePath);
            //预览路径
            vrFileInfo.setPathView(path);
            vrFileInfo.setName(newFileName);
            vrFileInfo.setSrcName(fileName);
            vrFileInfo.setSize(fileSize);
            vrFileInfo.setUuid(uuid);
            //vr配置
            vrFileInfo.setTotalMemory(vrFileInfoEP.getTotalMemory());
            vrFileInfo.setSecretkey(vrFileInfoEP.getSecretkey());
            vrFileInfo.setType(vrFileInfoEP.getType());
            vrFileInfo.setVersion(vrFileInfoEP.getVersion());
            this.vrFileInfoMapper.insertSelective(vrFileInfo);
            //id传给前端
            path = String.valueOf(vrFileInfo.getId());
            UploadResult result = new UploadResult(true,"上传成功",fileNameNoSuffix,fileNameNoSuffix,fileSize,newFilePath,path,suffix);
            return result;
        }catch (Exception e){
            throw new ServiceException("上传失败，请重新上传",e);
        }finally {
            if (fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new ServiceException("close error.",e);
                }
            }
        }

    }

    /**
     * 仅上传至本地服务器，然后调用这个接口执行线程上传至OSS云
     * @param inputStream
     * @param fileName
     * @return
     */
    public UploadResult uploadFlashFile(InputStream inputStream, String fileName){
        FileOutputStream fos = null;
        try {
            String suffix = FileInfoUtils.getFileSuffix(fileName);
            String fileNameNoSuffix = FileInfoUtils.getFileNameNoSuffix(fileName);
            String uuid = UUID.randomUUID().toString();
            String newFileName = uuid+"."+suffix;
            //写入临时文件夹
            String dateStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            String newFileTmpPath = uploadTmpPath+dateStr+"/"+uuid+"/"+newFileName;
            File newFileTmp = new File(newFileTmpPath);
            FileUtils.forceMkdir(newFileTmp.getParentFile());
            fos = new FileOutputStream(newFileTmp);
            IOUtils.copy(inputStream,fos);
            //获取文件相关信息
            long fileSize = newFileTmp.length();
            //flash 上传oss
            String newFilePath = apiPreFixPath + "webhtml" + "/" + dateStr + "/" + uuid + "/" + uuid + "." + suffix;
            //写入数据库
            FileInfo fileInfo = new FileInfo();
            fileInfo.setPath(newFilePath);
            fileInfo.setName(newFileName);
            fileInfo.setSrcName(fileName);
            fileInfo.setSize(fileSize);
            fileInfo.setSuffix(suffix);
            //获取md5 和sha1
            String md5Code = DigestUtils.getFileDigestCode(newFileTmp,"md5");
            String sha1Code = DigestUtils.getFileDigestCode(newFileTmp,"sha1");
            fileInfo.setMd5Code(md5Code);
            fileInfo.setSha1Code(sha1Code);
            this.fileInfoMapper.insertSelective(fileInfo);
            UploadResult result = new UploadResult(true, "上传成功", fileNameNoSuffix, fileNameNoSuffix, fileSize, newFilePath, "", suffix);
            return result;
        }catch (Exception e){
            throw new ServiceException("上传失败，请重新上传",e);
        }finally {
            if (fos!=null){
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new ServiceException("close error.",e);
                }
            }
        }
    }

    /**
     * 文件上产至清云数据，并保存返回对象
     * @param id
     * @param isCommit
     * @param path
     */
    @Transactional
    public void editOtherResInfo(Long id, Integer isCommit, String path) {
        log.info("异步上传文件到阿里云OSS..." + Thread.activeCount());
        String typeStr = "webhtml";
        String viewPath = path.replace( apiPreFixPath + typeStr + "/", uploadTmpPath);
        File newFileTmp = new File(viewPath);
        String uuid = viewPath.substring(viewPath.lastIndexOf("/") + 1, viewPath.lastIndexOf("."));
        String dateStr = viewPath.substring(uploadTmpPath.length(), uploadTmpPath.length() + 10);
        try {
            //解压缩并且上传服务器
            UnCompressor.unzip(newFileTmp,newFileTmp.getParentFile());
            //上传oss
            viewPath = aliOssService.unzipFlash(newFileTmp, newFileTmp.getParentFile(),uuid);
            if (StringUtils.isEmpty(viewPath)) {
                log.error("上传至OSS失败！viewPath 为空！资源ID = " + id + "viewPath = " + viewPath);
            }else {
                log.info("上传成功！viewPath = " + viewPath);
            }
            //把文件放入正式存储
            String saveDir = fileSavePath + typeStr + "/" + dateStr + "/" + uuid;
            this.fileAccessComp.writeDir(newFileTmp.getParentFile(),saveDir);
            // 更新数据库
            FileInfo fileInfo = this.getFileInfoByPath(path);
            fileInfo.setPathView(viewPath);
            fileInfoMapper.updateByPrimaryKeySelective(fileInfo);
        } catch (Exception e) {
            // 调用清云数据修改资源数据
            editOtherResById(id, 5, viewPath);
            log.error(e.getMessage(), e);
            throw new ServiceException("交互式微课上传失败！");
        }
        // 调用清云数据修改资源数据
        editOtherResById(id, isCommit, viewPath);
    }

    /**
     * 调用清云数据修改资源数据
     * @param id
     * @param isCommit
     * @param viewPath
     */
    public void editOtherResById(Long id, Integer isCommit, String viewPath){
        if (StringUtils.isEmpty(viewPath)) {
            isCommit = 5;
        }
        log.info("调用更改资源状态值");
        viewPath = URLEncoder.encode(viewPath);
        HttpTookit.doGet(coreDataHost + "/otherres/updateOtherresStatusAndFile?otherid=" + id + "&urlView=" + viewPath + "&status=" + isCommit, null, "utf-8", true);
        log.info("调用完成");
    }

    /**
     * 开启线程将本地文件上传至阿里OSS云
     * @param id
     * @param isCommit
     * @param localFilePath
     */
    public void asyncUpload(Long id, Integer isCommit, String localFilePath) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                editOtherResInfo(id, isCommit, localFilePath);
            }
        }).start();
    }

    /**
     * test
     * @param id
     */
    public synchronized void test(long id){
        Thread t = Thread.currentThread();
        System.out.println( "线程的ID：" + t.getId());
        System.out.println( "线程的名称：" + t.getName());
        System.out.println("线程数：" + t.activeCount());
        System.out.println("总线程数：" + Thread.activeCount());
        for (int i = 0; i < 10; i++) {
            try {
                if (i == 8) {
                    int a = 1/0;
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程  " + id + "  ** " + new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.sss").format(new Date()));
        }

    }


}
